//
//  HistoricVariablePlot.m
//  histoval
//
//  Created by Daniel Braun on 16/06/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "HistoricVariablePlot.h"
#import "HistoryVariable.h"
//#import "__HistoEntry.h"
#import "EDSortedArray.h"

@implementation HistoricVariablePlot

#define VALUE(he) ((he)->_value)

#define NEED_REDRAW do {\
	[cachedImage release];\
	cachedImage=nil;\
} while (0)

- (void) dealloc {
	[variables release];
	[date1 release];
	[date2 release];
	[minDate release];
	[maxDate release];
	[date1 release];
	[date2 release];
	[cachedImage release];
	[super dealloc];
}

- (id) init {
	self = [super init];
	if (self != nil) {
		variables=[[NSMutableArray arrayWithCapacity:10]retain];
		size=NSMakeSize(320,320);
	}
	return self;
}
- (id) initWithSize:(NSSize)s
{
	self=[self init];
	if (!self) return nil;
	size=s;
	return self;
}
- (void) addHistoryVariable:(HistoryVariable *)v
{
	NEED_REDRAW;
	[variables addObject:v];
	HistoEntry *a, *b;
	a=[v minimumObject];
	b=[v maximumObject];
	if (a) {
		NSDate *da=a->date;
		if (!minDate) minDate=[da retain];
		else if ([da compare:minDate]==NSOrderedAscending) {
			[minDate release];
			minDate=[da retain];
		}
	}
	if (b) {
		NSDate *db=b->date;
		if (!maxDate) maxDate=[db retain];
		else if ([db compare:maxDate]==NSOrderedDescending) {
			[maxDate release];
			maxDate=[db retain];
		}
	}
}
- (void) setDates:(NSDate *)d1 and:(NSDate *)d2
{
	[date1 release];
	date1=[d1 retain];
	[date2 release];
	date1=[d2 retain];
	NEED_REDRAW;
}
- (void) setFlags:(int)m
{
	if (m != flags) {
		flags=m;
		NEED_REDRAW;
	}
}

- (void) _plot
{
	NSRect r;
	r.origin.x=0; r.origin.y=0;
	r.size=size;

#define NLEGENDBP 1
	int i;
	int nvar=[variables count];
	if (!nvar) return;
	
	double minv,maxv;
	NSDate *d1=date1 ? date1 : minDate;
	NSDate *d2=date2 ? date2  : maxDate;
	HistoEntry *vref1=[[[HistoEntry alloc]initWithValue:0.0 date:d1]autorelease];
	
	NSBezierPath **bp=NSZoneMalloc(NSDefaultMallocZone(),(nvar+NLEGENDBP)*sizeof(NSBezierPath*));
	if (!bp) return;
	
	HistoryVariable *cumul=nil;
	if (flags & PLOT_ADD) {
		cumul=[[[HistoryVariable alloc]init]autorelease];
	}
	for (i=0; i<nvar; i++) {
		bp[i+NLEGENDBP]=[[[NSBezierPath alloc]init]autorelease];
		HistoEntry *e;
		HistoryVariable *_h=[variables objectAtIndex:i];
		BOOL first=YES;
		if (flags & PLOT_FILL) {
			[bp[i+1] moveToPoint:NSMakePoint([d1 timeIntervalSinceReferenceDate],0.0)];
			first=NO;
		}
		
		if (cumul) {
			if (i) {
				NSLog(@"break here\n");
			}
			HistoryVariable *sum=[[[HistoryVariable alloc]init]autorelease];
			e=[_h smallerOrEqualMember:vref1];
			if (!e) e=[_h minimumObject];
			for (; e ; e=[_h successorForObject:e]) {
				//double d=[e->date timeIntervalSinceReferenceDate];
				double v=VALUE(e);
				double v2=[cumul interpolatedDValueAtDate:e->date];
				v2=v+v2;
				[sum setDValue:v2 atDate:e->date];
			}
			e=[cumul smallerOrEqualMember:vref1];
			if (!e) e=[cumul minimumObject];
			for (; e ; e=[cumul successorForObject:e]) {
				//double d=[e->date timeIntervalSinceReferenceDate];
				double v=VALUE(e);
				double v2=[_h interpolatedDValueAtDate:e->date];
				v2=v+v2;
				[sum setDValue:v2 atDate:e->date];
			}	
			_h=sum;
			cumul=sum;
		}
		int c=0;
		e=[_h smallerOrEqualMember:vref1];
		if (!e) e=[_h minimumObject];
		for (; e ; e=[_h successorForObject:e]) {
			double d=[e->date timeIntervalSinceReferenceDate];
			double v=VALUE(e);
			if (cumul) {
				//double pv=
			}
			if (first && !i) {
				minv=v;
				maxv=v;
			} else {
				if (v<minv) minv=v;
				if (v>maxv) maxv=v;
			}
			if (first) {
				first=NO;
				[bp[i+NLEGENDBP] moveToPoint:NSMakePoint(d,v)];
			} else {
				[bp[i+NLEGENDBP] lineToPoint:NSMakePoint(d,v)];
			}
			// stop after date2
			c++;
			if ([e->date compare:d2] == NSOrderedDescending) {
				NSLog(@"stop d=%@, maxd=%@\n", e->date, d2);
				break;
			}
		}
		if (flags & PLOT_FILL) {
			[bp[i+NLEGENDBP] lineToPoint:NSMakePoint([d2 timeIntervalSinceReferenceDate],0.0)];
		}
		NSLog(@"var %d, got %d points\n", i, c);
	}
	if ((flags & PLOT_MIN0) && (minv>0)) minv=0.0;
	bp[0]=[[[NSBezierPath alloc]init]autorelease];
	[bp[0] moveToPoint:NSMakePoint([d1 timeIntervalSinceReferenceDate],0.0)];
	[bp[0] lineToPoint:NSMakePoint([d2 timeIntervalSinceReferenceDate],0.0)];
	
	NSAffineTransform *af1=[NSAffineTransform transform];
	[af1 scaleXBy:1/([d2 timeIntervalSinceReferenceDate]-[d1 timeIntervalSinceReferenceDate]) yBy:1/(maxv-minv)];
	[af1 translateXBy:-[d1 timeIntervalSinceReferenceDate] yBy:-minv];

	NSAffineTransform *af2=[NSAffineTransform transform];
	[af2 scaleXBy:size.width yBy:size.height];
	//[af1 appendTransform:af2];
	for (i=nvar+NLEGENDBP-1; i>=0; i--) {
		if (i<NLEGENDBP) {
			[[NSColor whiteColor]set];
		} else {
			float hue=0.9;
			if (nvar>1) hue=0.05+0.9*((float)(i-NLEGENDBP))/(nvar-1);
			NSLog(@"hue %f (i=%d nvar %d)\n", hue,i, nvar);
			[[NSColor colorWithDeviceHue:hue 
					 saturation:1.0 
					 brightness:0.9
					      alpha:1.0]set];
			

		}
		[bp[i]transformUsingAffineTransform:af1];
		[bp[i]transformUsingAffineTransform:af2];
		if ((i>=NLEGENDBP) && (flags & PLOT_FILL)) {
			[bp[i] fill];
		} else {
			[bp[i] stroke];
		}
	}
	NSZoneFree(NSDefaultMallocZone(),bp);
}
	
- (NSImage *) plotImage
{
	if (cachedImage) return cachedImage;
	
	cachedImage=[[NSImage alloc]initWithSize:size];
	if (!cachedImage) return nil;
	[cachedImage lockFocus];
	[self _plot];
	[cachedImage unlockFocus];
	return cachedImage;
}
	
	
@end
